/**
 *
 */
package name.yzhu.httpserver;

import java.io.IOException;
import java.util.Calendar;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jetty.servlet.DefaultServlet;

import name.yzhu.common.ErrorCoder;
import name.yzhu.common.conf.IConfigurable;
import name.yzhu.common.conf.IConfigure;


/**
 * the base class of servlet 
 * @author yhzhu
 *
 */
public abstract class AbstractHttpServlet extends DefaultServlet implements IConfigurable {
	private static final Log LOG = LogFactory.getLog(AbstractHttpServlet.class);
	/**
	 *
	 */
	private static final long serialVersionUID = 1979815285612672861L;

	protected IHttpPermission httpPermission = null;
	protected IErrorReport errorReport = null;
	protected ErrorCoder errCode;
	protected IConfigure conf = null;
	
	public AbstractHttpServlet() {
		httpPermission = getHttpPermissionFactory();
		errCode = new ErrorCoder();
		errCode.addErrorCodeMap(HttpserverConstant.ERRCODE_NOTFOUND_HRM, HttpserverConstant.NO_FIND_HRM_NAME);
	}

	public abstract String getContextRoot() ;

	public abstract String getContextPath() ;

	protected void process(HttpServletRequest req,
			 HttpServletResponse resp)throws ServletException, IOException{}
	
	protected void process(HttpServletRequest req,
			 HttpServletResponse resp, HttpRequestType requestType)throws ServletException, IOException{}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		doPost(req, resp);
	}

	static public String printQuery(HttpServletRequest req) {
		StringBuilder sb = new StringBuilder();
		Enumeration<String> nameEnum = req.getParameterNames();
		while (nameEnum.hasMoreElements()) {
			String name = nameEnum.nextElement();
			if (sb.length() > 0) {
				sb.append("&");
			} else {
				sb.append("?");
			}
			sb.append(name).append("=").append(req.getParameter(name));
		}
		return sb.toString();
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		String q = printQuery(req);
		String url = "http://"+req.getLocalName()+":"+req.getLocalPort()+req.getServletPath()+q;
		String reqStr = "[beginning request: "+url+"] from "+req.getRemoteHost()+":"+req.getRemotePort();
		LOG.info(reqStr);
		Calendar beginTime = java.util.Calendar.getInstance();
        try{
        	if (conf != null && conf.getBoolean("defaults.for.version.skip", false)){
        		//TODO: should we need to check version
        	}
        	HttpReturnData retData = new HttpReturnData();
			if (!this.httpPermission.check(req, HttpRequestType.Post, retData)){
				LOG.warn("the permission is refused "+req.getRemoteHost());
				outputStatus(resp, ErrorCoder.ERRCODE_NO_PERMISSION,
						this.errCode.getErrorComment(ErrorCoder.ERRCODE_NO_PERMISSION));
				resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
				return;
			}
			
			resp.setStatus(HttpServletResponse.SC_OK);
			resp.setContentType("text/html; charset=UTF-8");
			resp.setCharacterEncoding(name.yzhu.common.CommonConstant.UTF_8_STRING);
			
			req.setCharacterEncoding(name.yzhu.common.CommonConstant.UTF_8_STRING);
			process(req, resp);
			resp.flushBuffer();
        }
        finally{
			Calendar endTime = java.util.Calendar.getInstance();
			reqStr = "[ended request: "+url+"] from "+req.getRemoteHost()+":"+req.getRemotePort()
					+" cost: "+ String.valueOf((endTime.getTimeInMillis() - beginTime.getTimeInMillis())) +"ms";
			LOG.info(reqStr);
        }
	}

	protected void outputStatus(HttpServletResponse resp, int status,
			String errorInfo) throws IOException {;

		if (this.errorReport != null) {
			resp.getWriter().print(
					errorReport.getErrorMessage(status, errorInfo));
		} else {
			resp.getWriter().println("status:" + status);
			if (errorInfo != null) {
				resp.getWriter().println();
				resp.getWriter().println(errorInfo);
			}
		}
	}
	
	protected IHttpPermission getHttpPermissionFactory() {
		return new IHttpPermission(){

			@Override
			public boolean check(HttpServletRequest request,
					HttpRequestType type, HttpReturnData retData) {
				return true;
			}};
	}
	
	public IErrorReport getErrorReport() {
		return errorReport;
	}

	public void setErrorReport(IErrorReport errorReport) {
		this.errorReport = errorReport;
	}

	public ErrorCoder getErrCode() {
		return errCode;
	}

	public void setErrCode(ErrorCoder errCode) {
		this.errCode = errCode;
	}

	@Override
	public void setConfig(IConfigure conf) {
		this.conf  = conf;
	}

	@Override
	public IConfigure getConfig() {
		return conf;
	}
}
